#include "StdAfx.h"
#include "GraphicDevice.h"
#include "stdlis.h"
#include "WindowSetup.h"
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>

GraphicDevice::GraphicDevice(void)
{
	_driverType = D3D_DRIVER_TYPE_NULL;
	_pSwapChain = NULL;
	_pd3dDevice = NULL;
	_featureLevel = D3D_FEATURE_LEVEL_11_0;
	_pContext = NULL;
	_pRenderTargetView = NULL;
	_pDepthStencil = NULL;
	_pDepthStencilView = NULL;
	_Height = 0;
	_Width = 0;
}


GraphicDevice::~GraphicDevice(void)
{
}

HRESULT GraphicDevice::CreateDevice(void)
{
	HRESULT hr;

	RECT rc;
	GetClientRect( WindowSetup::GetWindow(), &rc );
	_Width = rc.right - rc.left;
	_Height = rc.bottom - rc.top;

	UINT createDeviceFlags = 0;
#ifdef _DEBUG
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	D3D_DRIVER_TYPE driverTypes[] =
	{
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE,
	};
	UINT numDriverTypes = ARRAYSIZE( driverTypes );

	D3D_FEATURE_LEVEL featureLevels[] =
	{
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
	};
	UINT numFeatureLevels = ARRAYSIZE( featureLevels );

	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory( &sd, sizeof( sd ) );
	sd.BufferCount = 1;
	sd.BufferDesc.Width = _Width;
	sd.BufferDesc.Height = _Height;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = WindowSetup::GetWindow();
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;

	for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
	{
		_driverType = driverTypes[driverTypeIndex];
		hr = D3D11CreateDeviceAndSwapChain( NULL, _driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
			D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &_featureLevel, &_pContext );
		if( SUCCEEDED( hr ) )
			break;
	}

	ASSERT(hr == S_OK);
	ASSERT(_pd3dDevice);
	ASSERT(_pContext);

	return hr;
}

HRESULT GraphicDevice::CreateBuffers(void)
{
	HRESULT hr;

	ID3D11Texture2D* pBackBuffer = NULL;
	CHECKHR(_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer ));

	hr = _pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &_pRenderTargetView );
	pBackBuffer->Release();
	CHECKHR(hr);
	
	// Create depth stencil texture
	D3D11_TEXTURE2D_DESC descDepth;
	ZeroMemory( &descDepth, sizeof(descDepth) );
	descDepth.Width = _Width;
	descDepth.Height = _Height;
	descDepth.MipLevels = 1;
	descDepth.ArraySize = 1;
	descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	descDepth.SampleDesc.Count = 1;
	descDepth.SampleDesc.Quality = 0;
	descDepth.Usage = D3D11_USAGE_DEFAULT;
	descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	descDepth.CPUAccessFlags = 0;
	descDepth.MiscFlags = 0;
	CHECKHR(_pd3dDevice->CreateTexture2D( &descDepth, NULL, &_pDepthStencil ));

	// Create the depth stencil view
	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
	ZeroMemory( &descDSV, sizeof(descDSV) );
	descDSV.Format = descDepth.Format;
	descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	descDSV.Texture2D.MipSlice = 0;
	CHECKHR(_pd3dDevice->CreateDepthStencilView( _pDepthStencil, &descDSV, &_pDepthStencilView ));
	_pContext->OMSetRenderTargets( 1, &_pRenderTargetView, _pDepthStencilView );
	return hr;
}

HRESULT GraphicDevice::SetViewPort(void)
{
	D3D11_VIEWPORT vp;
	vp.Width = (FLOAT)_Width;
	vp.Height = (FLOAT)_Height;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	_pContext->RSSetViewports( 1, &vp );
	return S_OK;
}

HRESULT GraphicDevice::CompileShaders(void)
{
	HRESULT hr;
	ID3DBlob* pVSBlob = NULL;
	CHECKHR(GfxHelper::CompileShaderFromFile( "Tutorial07.fx", "VS", "vs_4_0", &pVSBlob ));
	return S_OK;
}

HRESULT GraphicDevice::OnInit(void)
{
	HRESULT hr;

	CHECKHR(CreateDevice());
	CHECKHR(CreateBuffers());
	CHECKHR(SetViewPort());
	//CHECKHR(CompileShaders());

	return S_OK;
}

HRESULT GraphicDevice::OnUninit(void)
{
	SAFERELEASE(_pd3dDevice);
	SAFERELEASE(_pContext);
	SAFERELEASE(_pSwapChain);
	SAFERELEASE(_pRenderTargetView);
	SAFERELEASE(_pDepthStencil);
	SAFERELEASE(_pDepthStencilView);
	return S_OK;
}
